/**
 * Created by LiYang on 16-9-27 下午2:07.
 */

package com.example.db.common;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;


import com.example.db.DBSerializable;
import com.example.db.callback.ConnectionCallback;
import com.example.db.callback.CursorCallback;
import com.example.db.generate.EntityGenerateHandler;
import com.example.db.generate.GenerateHandler;
import com.example.db.mapper.ModelMapperHandler;
import com.example.db.mapper.RowMapperHandler;
import com.example.db.mapper.SingleMapperHandler;
import com.example.db.support.DefaultCursorFactory;
import com.example.db.utils.BeanUtil;
import com.example.db.utils.ObjectUtil;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;


public abstract class EntityTemplate<T extends DBSerializable> extends DataAccessor {
    private final RowMapperHandler <T> rowMapper;
    private final GenerateHandler <T> generateHandler;

    protected EntityTemplate(Context context, String dbName, int version, Class<T> klass) {
        super(context, dbName, new DefaultCursorFactory(), version);
        this.generateHandler = new EntityGenerateHandler<T>(klass);
        this.rowMapper = new ModelMapperHandler<T>(klass);
    }

    protected EntityTemplate(Context context, String dbName, int version,
                             GenerateHandler<T> generateHandler, RowMapperHandler<T> rowMapper) {
        super(context, dbName, new DefaultCursorFactory(), version);
        this.generateHandler = generateHandler;
        this.rowMapper = rowMapper;
    }

    @Override
    protected String getTableName() {
        return generateHandler.getTableName();
    }

    protected abstract String getPkName();

    @Override
    protected String getCreateSQL() {
        return generateHandler.createTable();
    }

    /**
     * 清空表数据,等价于 {@code delete(null)}
     *
     * @return 影响行数
     */
    public int truncate() throws SQLException {
        return delete(null);
    }

    /**
     * 插入一个实体
     */
    public long insert(T entity) throws SQLException {
        ObjectUtil.assertExpression(entity != null, "entity must be not null");
        return insert(generateHandler.getContentValues(entity));
    }

    /**
     * 更新一个实体
     */
    public int update(T entity) throws SQLException {
        String pkName = getPkName();
        ObjectUtil.assertExpression(entity != null, "entity must be not null");
        String[] params = {String.valueOf(BeanUtil.getFieldValue(entity, pkName))};
        return update(generateHandler.getContentValues(entity), pkName + " = ?", params);
    }

    /**
     * 更新一个实体
     */
    public int update(T entity, String[] columns) throws SQLException {
        String pkName = getPkName();
        ObjectUtil.assertExpression(entity != null, "entity must be not null");
        String[] params = {String.valueOf(BeanUtil.getFieldValue(entity, pkName))};
        return update(generateHandler.getContentValues(entity, columns), pkName + " = ?", params);
    }

    /**
     * 删除一行
     */
    public int delete(long id) throws SQLException {
        ObjectUtil.assertExpression(id > 0, "entity must be gt zero");
        String[] params = {String.valueOf(id)};
        return delete(getPkName() + " = ?", params);
    }

    public T select(long id) throws SQLException {
        String sql = generateHandler.selectSql(getPkName() + "=?", "");
        String[] params = {String.valueOf(id)};

        return execute(sql, params, new CursorCallback<T>() {
                           public T doInCursor(Cursor cursor) throws SQLException {
                               if (cursor.moveToNext()) {
                                   return rowMapper.rowMapper(cursor);
                               }
                               return null;
                           }
                       }
        );
    }

    /**
     * 查询单条数据，并转为相应类型的实体
     */
    public T select(String condition, String... params) throws SQLException {
        String sql = generateHandler.selectSql(condition, "");

        return execute(sql, params, new CursorCallback<T>() {
                           public T doInCursor(Cursor cursor) throws SQLException {
                               if (cursor.moveToNext()) {
                                   return rowMapper.rowMapper(cursor);
                               }
                               return null;
                           }
                       }
        );
    }

    /**
     * 查询数据条数
     */
    public long selectCount(String condition, String... params) throws SQLException {
        String sql = generateHandler.selectFunSql(new String[]{"COUNT(1)"}, condition);
        final RowMapperHandler<Long> rowMapper = new SingleMapperHandler<Long>();
        return execute(sql, params, new CursorCallback<Long>() {
                           public Long doInCursor(Cursor cursor) throws SQLException {
                               if (cursor.moveToNext()) {
                                   return rowMapper.rowMapper(cursor);
                               }
                               return null;
                           }
                       }
        );
    }

    /**
     * 查询多条数据，并转为相应类型的实体列表
     */
    public List<T> selectList() throws SQLException {
        return selectListWithConditionAndSort("", "");
    }

    /**
     * 查询多条数据，并转为相应类型的实体列表（带有查询条件与查询参数）
     */
    public List<T> selectListWithCondition(String condition, String... params) throws SQLException {
        return selectListWithConditionAndSort(condition, "", params);
    }

    /**
     * 查询多条数据，并转为相应类型的实体列表（带有排序方式）
     */
    public List<T> selectListWithSort(String sort) throws SQLException {
        return selectListWithConditionAndSort("", sort);
    }

    /**
     * 查询多条数据，并转为相应类型的实体列表（带有查询条件、排序方式与查询参数）
     */
    public List<T> selectListWithConditionAndSort(String condition, String sort, String... params)
            throws SQLException {
        String sql = generateHandler.selectSql(condition, sort);
        return execute(sql, params, new CursorCallback<List<T>>() {
                           public List<T> doInCursor(Cursor cursor) throws SQLException {
                               List<T> values = new ArrayList<T>();
                               while (cursor.moveToNext()) {
                                   values.add(rowMapper.rowMapper(cursor));
                               }
                               return values;
                           }
                       }
        );
    }

    /**
     * 查询多条数据，并转为列表（分页方式）
     */
    public List<T> selectListForPager(int pageNumber, int pageSize, String condition, String sort,
                                      String... params) throws SQLException {
        String sql = generateHandler.selectSqlForPager(pageNumber, pageSize, condition, sort);
        return execute(sql, params, new CursorCallback<List<T>>() {
                           public List<T> doInCursor(Cursor cursor) throws SQLException {
                               List<T> values = new ArrayList<T>();
                               while (cursor.moveToNext()) {
                                   values.add(rowMapper.rowMapper(cursor));
                               }
                               return values;
                           }
                       }
        );
    }

    /**
     * 根据列名查询单条数据，并转为相应类型的实体
     */
    public T selectColumn(String[] columns, String condition, String... params)
            throws SQLException {
        String sql = generateHandler.selectCustomSql(columns, condition, "");
        return execute(sql, params, new CursorCallback<T>() {
                           public T doInCursor(Cursor cursor) throws SQLException {
                               if (cursor.moveToNext()) {
                                   return rowMapper.rowMapper(cursor);
                               }
                               return null;
                           }
                       }
        );
    }

    /**
     * 根据列名查询多条数据，并转为相应类型的实体列表
     */
    public List<T> selectColumnList(String[] columns, String condition, String sort,
                                    String... params) throws SQLException {
        String sql = generateHandler.selectCustomSql(columns, condition, sort);
        return execute(sql, params, new CursorCallback<List<T>>() {
                           public List<T> doInCursor(Cursor cursor) throws SQLException {
                               List<T> values = new ArrayList<T>();
                               while (cursor.moveToNext()) {
                                   values.add(rowMapper.rowMapper(cursor));
                               }
                               return values;
                           }
                       }
        );
    }

    /**
     * 插入一条数据
     */
    public long insert(final ContentValues values) throws SQLException {
        if (values == null || values.size() == 0) {
            return 0l;
        }
        return execute(new ConnectionCallback<Long>() {
                           public Long doInConnection(SQLiteDatabase sqlSession)
                                   throws SQLException {
                               return sqlSession
                                       .insert(generateHandler.getTableName(), null, values);
                           }
                       }
        );
    }

    /**
     * 更新相关数据
     */
    public int update(final ContentValues values, final String condition, final String... params)
            throws SQLException {
        if (values == null || values.size() == 0) {
            return 0;
        }
        return execute(new ConnectionCallback<Integer>() {
                           public Integer doInConnection(SQLiteDatabase sqlSession)
                                   throws SQLException {
                               return sqlSession
                                       .update(generateHandler.getTableName(), values, condition,
                                               params
                                       );
                           }
                       }
        );
    }

    /**
     * 删除相关数据
     */
    public int delete(final String condition, final String... params) throws SQLException {
        return execute(new ConnectionCallback<Integer>() {
                           public Integer doInConnection(SQLiteDatabase sqlSession)
                                   throws SQLException {
                               return sqlSession
                                       .delete(generateHandler.getTableName(), condition, params);
                           }
                       }
        );
    }

    /**
     * 更新一个实体（带有主键名）
     */
    @Deprecated
    public int update(T entity, String pkName) throws SQLException {
        ObjectUtil.assertExpression(entity != null, "entity must be not null");
        String[] params = {String.valueOf(BeanUtil.getFieldValue(entity, pkName))};
        return update(generateHandler.getContentValues(entity), pkName + " = ?", params);
    }

    /**
     * 删除一个实体（可指定主键名）
     */
    @Deprecated
    public int delete(T entity, String pkName) throws SQLException {
        ObjectUtil.assertExpression(entity != null, "entity must be not null");
        String[] params = {String.valueOf(BeanUtil.getFieldValue(entity, pkName))};
        return delete(pkName + " = ?", params);
    }
}